package com.itheima.note.service.impl;

import com.alibaba.fastjson.JSON;
import com.itheima.apis.book.IBookClient;
import com.itheima.apis.user.IUserClient;
import com.itheima.model.book.vos.BookVo;
import com.itheima.model.common.dtos.PageResponseResult;
import com.itheima.model.common.dtos.ResponseResult;
import com.itheima.model.common.enums.AppHttpCodeEnum;
import com.itheima.model.note.dtos.NoteDto;
import com.itheima.model.note.pojos.Note;
import com.itheima.model.user.pojos.User;
import com.itheima.model.user.vos.AuthorVo;
import com.itheima.note.service.NoteAuditService;
import com.itheima.note.utils.NoteStatisticsUtil;
import com.itheima.utils.thread.MpThreadLocalUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class NoteServiceImpl {

    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private IUserClient userClient;
    @Autowired
    private IBookClient bookClient;
    @Autowired
    private NoteStatisticsUtil noteStatisticsUtil;
    @Autowired
    private NoteAuditService noteAuditService;

    /**
     * 基于MongoTemplate实现分页查询笔记列表
     *
     * @param dto 分页及筛选参数
     * @return 分页结果
     */
    public ResponseResult getNoteList(NoteDto dto) {
        // 1. 参数校验
        if (dto == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        dto.checkParam();

        // 2. 处理分页参数
        int page = dto.getPage();
        int size = dto.getSize();
        int skip = (page - 1) * size; // 计算跳过的记录数

        try {
            // 3. 构建查询条件
            Query query = new Query();

            // 3.1 处理ownFlag筛选（1-查询自己的笔记，0或null-查询全部公开笔记）
            Integer ownFlag = dto.getOwnFlag();
            if (ownFlag != null && ownFlag.equals(NoteDto.QUERY_OWN)) {
                // 3.1.1 查询自己的笔记：不筛选status，只限制用户
                User user = MpThreadLocalUtil.getUser();
                if (user == null) {
                    return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
                }
                query.addCriteria(Criteria.where("author.id").is(user.getId()));
            } else {
                // 3.1.2 查询公开笔记：必须筛选status=已通过，不限制用户
                query.addCriteria(Criteria.where("status").is(Note.APPROVED));
            }

            // 3.2 按书籍ID筛选（如果DTO中有bookId）
            if (dto.getBookId() != null) {
                query.addCriteria(Criteria.where("book.id").is(dto.getBookId()));
            }

            // 3.3 排序：按创建时间倒序（最新的在前）
            query.with(Sort.by(Sort.Direction.DESC, "create_time"));

            // 4. 执行分页查询
            // 4.1 先查询总条数
            long total = mongoTemplate.count(query, Note.class);

            // 4.2 再查询当前页数据
            List<Note> notes = mongoTemplate.find(
                    query.skip(skip).limit(size),
                    Note.class
            );

            // 4.3 批量设置统计数据
            noteStatisticsUtil.batchSetNoteStatistics(notes);

            // 5. 封装分页结果
            PageResponseResult responseResult = new PageResponseResult(page, size, (int) total);
            responseResult.setData(notes);

            return responseResult;

        } catch (Exception e) {
            log.error("查询笔记列表失败", e);
            return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, "查询笔记失败");
        }
    }



    /**
     * 新增笔记
     *
     * @param dto
     * @return
     */
    public ResponseResult addNote(NoteDto dto) {
        // 参数校验
        User user = validateAndGetUser(dto);
        if (user == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        Note note = buildNoteFromDto(dto, user);
        mongoTemplate.save(note);
        
        // 提交审核
        noteAuditService.submitAudit(note);
        
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 修改笔记
     *
     * @param dto
     * @return
     */
    public ResponseResult updateNote(NoteDto dto) {
        // 参数校验
        User user = validateAndGetUser(dto);
        if (user == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        Note note = buildNoteFromDto(dto, user);
        mongoTemplate.save(note);
        
        // 提交审核
        noteAuditService.submitAudit(note);
        
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 参数校验公共方法
     * 返回 User 对象，如果校验失败返回 null
     */
    private User validateAndGetUser(NoteDto dto) {
        User user = MpThreadLocalUtil.getUser();
        if (user == null || dto == null) {
            return null;
        }
        return user;
    }

    /**
     * 从 DTO 构建 Note 对象的公共方法
     */
    private Note buildNoteFromDto(NoteDto dto, User user) {
        Note note = new Note();
        BeanUtils.copyProperties(dto, note);
        note.setStatus(Note.PENDING);
        note.setCreateTime(new Date());
        note.setUpdateTime(new Date());
        
        // 设置作者信息对象
        AuthorVo authorVo = getAuthorVo(user);
        note.setAuthor(authorVo);
        
        // 设置图书信息对象
        BookVo bookVo = getBookVo(dto.getBookId());
        note.setBook(bookVo);
        
        return note;
    }

    /**
     * 获取作者信息对象
     */
    private AuthorVo getAuthorVo(User user) {
        try {
            ResponseResult authorResult = userClient.getAuthorVo(user.getId());
            if (authorResult.getCode().equals(200)) {
                String authorJSON = JSON.toJSONString(authorResult.getData());
                return JSON.parseObject(authorJSON, AuthorVo.class);
            } 
        } catch (Exception e) {
            log.error("获取作者信息失败，使用用户基本信息", e);
            AuthorVo authorVo = new AuthorVo();
            BeanUtils.copyProperties(user, authorVo);
            return authorVo;
        }
        return null;
    }

    /**
     * 获取图书信息对象
     */
    private BookVo getBookVo(Integer bookId) {
        try {
            ResponseResult<BookVo> bookResult = bookClient.getBookVo(bookId);
            if (bookResult.getCode().equals(200)) {
                String bookJSON = JSON.toJSONString(bookResult.getData());
                return JSON.parseObject(bookJSON, BookVo.class);
            }
        } catch (Exception e) {
            log.error("获取图书信息失败，bookId: {}", bookId, e);
        }
        return null;
    }

    /**
     * 根据图书id聚类统计用户笔记数
     *
     * @param userId
     * @return
     */
    public ResponseResult countNotesByBookForUser(Integer userId) {
        if (userId == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        try {
            // 1.构建聚合管道
            List<AggregationOperation> operations = new ArrayList<>();

            // 筛选：用户ID匹配
            operations.add(Aggregation.match(
                    Criteria.where("author.id").is(userId)
            ));

            // 按图书ID分组统计数量
            operations.add(Aggregation.group("book.id")
                    .count().as("count")
            );

            // 执行聚合查询
            Aggregation aggregation = Aggregation.newAggregation(operations);
            AggregationResults<Map> results = mongoTemplate.aggregate(
                    aggregation,
                    Note.class,
                    Map.class // 临时用Map接收聚合结果（_id为bookId，count为数量）
            );

            // 2. 将聚合结果转换为 Map<bookId, count>
            Map<Integer, Integer> bookNoteCountMap = results.getMappedResults().stream()
                    .collect(Collectors.toMap(
                            // 键：_id字段（bookId），转换为Integer
                            doc -> Integer.parseInt(doc.get("_id").toString()),
                            // 值：count字段，转换为Long
                            doc -> Integer.parseInt(doc.get("count").toString()),
                            // 若有重复bookId（理论上不会，因为按bookId分组），取第一个值
                            (existing, replacement) -> existing
                    ));
            return ResponseResult.okResult(bookNoteCountMap);
        } catch (Exception e) {
            log.error("统计用户[{}]的图书笔记数失败", userId, e);
            return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, "统计笔记数失败");
        }

    }

    /**
     * 删除笔记
     * @param id
     * @return
     */
    public ResponseResult deleteNote(String id) {
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(id));
        mongoTemplate.remove(query, Note.class);
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }
    
    /**
     * 根据ID获取笔记详情
     * @param id 笔记ID
     * @return
     */
    public ResponseResult getNoteById(String id) {
        try {
            // 构建查询条件
            Query query = new Query();
            query.addCriteria(Criteria.where("_id").is(id));
            
            // 查询笔记
            Note note = mongoTemplate.findOne(query, Note.class);
            
            if (note == null) {
                return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "笔记不存在");
            }
            
            // 设置统计数据（点赞数、评论数、分享数等）
            noteStatisticsUtil.setNoteStatistics(note);
            
            return ResponseResult.okResult(note);
            
        } catch (Exception e) {
            log.error("获取笔记详情失败，noteId: {}", id, e);
            return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, "获取笔记详情失败");
        }
    }
}